package com.plm.blogs.shiro;

import com.plm.blogs.entity.User;
import com.plm.blogs.service.UserService;
import com.plm.blogs.utils.Encrypt;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.regex.Pattern;

/**
 * @author Limi
 * @create 2019-01-09 18:21
 */
@Slf4j
public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    /**
     * 提供用户信息，返回权限信息
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        log.info("---------------------------->授权认证：");
        SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
        /*String userName=(String) principals.getPrimaryPrincipal();
        String userId=userService.findUserIdByName(userName);
        Set<SysUserRole> roleIdSet=userService.findRoleIdByUid( Integer.parseInt(userId) );
        Set<String> roleSet=new HashSet<>();
        Set<Integer>  pemissionIdSet=new HashSet<>();
        Set<String>  pemissionSet=new HashSet<>();
        for(SysUserRole roleInfo : roleIdSet) {
            int roleId=roleInfo.getRoleId();
            roleSet.add( userService.findRoleByRoleId( roleId  ) );
            //将拥有角色的所有权限放进Set里面，也就是求Set集合的并集
            //由于我这边的数据表设计得不太好，所以提取set集合比较麻烦
            pemissionIdSet.addAll( userService.findPermissionIdByRoleId(  roleId ));
        }
        for(int permissionId : pemissionIdSet) {
            String permission= userService.findPermissionById( permissionId ).getPermission() ;
            pemissionSet.add(  permission );
        }
        // 将角色名称组成的Set提供给授权info
        authorizationInfo.setRoles( roleSet );
        // 将权限名称组成的Set提供给info
        authorizationInfo.setStringPermissions(pemissionSet);*/

        return authorizationInfo;
    }

    /**
     *  提供帐户信息，返回认证信息
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String phoneRegx = "^[1](([3][0-9])|([4][5,6,7,8,9])|([5][^4,6,9])|([6][6])|([7][3,4,5,6,7,8])|([8][0-9])|([9][8,9]))[0-9]{8}$";
        //String emailRegx = "/^\\w+((-\\w+)|(\\.\\w+))*\\@[A-Za-z0-9]+((\\.|-)[A-Za-z0-9]+)*\\.[A-Za-z0-9]+$/";

        log.info("---------------------------->登陆验证:");
        // 获取界面中输入的用户名和密码
        String phoneOrEmail = (String) token.getPrincipal();
        String password = new String((char[])token.getCredentials());
        log.info("认证登录：username is {}", phoneOrEmail);
        log.info("认证登录：password is {}", password);

        // 通过用户名获取用户信息
        User user;
        if (Pattern.matches(phoneRegx, phoneOrEmail)) {
            user = userService.findByPhone(phoneOrEmail);
        } else {
            user = userService.findByEmail(phoneOrEmail);
        }
        if (user == null) {
            throw new UnknownAccountException("用户名或密码错误!");
        }
        String encryptPassword = Encrypt.encrypt(password, user.getPhone());
        if (!encryptPassword.equals(user.getPassword())) {
            throw new IncorrectCredentialsException("用户名或密码错误!");
        }
        if (user.getStatus().equals("0")) {
            throw new LockedAccountException("账号已被锁定!");
        }

        //密码可以通过SimpleHash加密，然后保存进数据库。
        //此处是获取数据库内的账号、密码、盐值，保存到登陆信息info中
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                user,
                user.getPassword(),
                ByteSource.Util.bytes(user.getPhone()),
                getName());

        log.info("认证登录的用户信息：user is {}", user);
        Session session = SecurityUtils.getSubject().getSession();
        session.setAttribute("user", user);

        return authenticationInfo;
    }

}
